package org.example.netty.test.nio.java;

import io.netty.util.internal.StringUtil;
import org.example.netty.test.nio.bean.User;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Objects;
import java.util.Scanner;

/**
 * @author zp
 * @description: 聊天客户端
 * @date: 2023/3/2 19:13
 */
public class ChatSocketChannel {

    private final int port = 8080;
    private final String seperator = "|";
    private final Charset charset = StandardCharsets.UTF_8;    //字符集
    private final ByteBuffer buffer = ByteBuffer.allocate(1024);
    private SocketChannel _self;
    private Selector selector;
    private String name = "";
    private boolean flag = true;    //服务端断开，客户端的读事件不会一直发生（与服务端不一样）

    Scanner scanner = new Scanner(System.in);

    public void startClient() throws IOException {
        //客户端初始化固定流程：4步
        selector = Selector.open();                                //1.打开Selector
        _self = SocketChannel.open(new InetSocketAddress(port));//2.连接服务端，这里默认本机的IP
        _self.configureBlocking(false);                            //3.配置此channel非阻塞
        _self.register(selector, SelectionKey.OP_READ);            //4.将channel的读事件注册到选择器

        /*
         * 因为等待用户输入会导致主线程阻塞
         * 所以用主线程处理输入，新开一个线程处理读数据
         */
        new Thread(new ClientReadThread()).start();    //开一个异步线程处理读
        String input = "";
        while (flag) {
            input = scanner.nextLine();
            if (StringUtil.isNullOrEmpty(input)) {
                System.out.println("不允许输入空串！");
                // 如果姓名没有初始化，且长度为1.说明当前在设置姓名
            } else if (!StringUtil.isNullOrEmpty(input) || StringUtil.isNullOrEmpty(name)) {
                if (input.startsWith("@") && !input.contains("|")) {
                    System.out.println("@ 他人输入不合法，请重新输入：");
                    continue;
                }
                try {
                    _self.write(charset.encode(input));
                } catch (Exception e) {
                    System.out.println(e.getMessage() + "客户端主线程退出连接！！");
                }
            }

        }
    }

    private class ClientReadThread implements Runnable {
        @Override
        public void run() {
            Iterator<SelectionKey> ikeys;
            SelectionKey key;
            SocketChannel client;
            try {
                while (flag) {
                    selector.select();    //调用此方法一直阻塞，直到有channel可用
                    ikeys = selector.selectedKeys().iterator();
                    while (ikeys.hasNext()) {
                        key = ikeys.next();
                        if (key.isReadable()) {    //处理读事件
                            client = (SocketChannel) key.channel();
                            buffer.clear();
                            StringBuilder msg = new StringBuilder();
                            try {
                                while (client.read(buffer) > 0) {
                                    buffer.flip();    //将写模式转换为读模式
                                    msg.append(charset.decode(buffer));
                                }
                            } catch (IOException en) {
                                System.out.println(en.getMessage() + ",客户端'" + key.attachment().toString() + "'读线程退出！！");
                                key.attach(null);
                                stopMainThread();
                            }

                            String message = msg.toString();

                            if (StringUtil.isNullOrEmpty(message)) {
                                continue;
                            }
                            if (message.contains("您的昵称通过验证")) {
                                if (message.contains("您的昵称通过验证")) {
                                    String[] nameValid = message.split("&");
                                    name = nameValid[1];
                                }
                            }
                            System.out.println(message);
                        }
                        ikeys.remove();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void stopMainThread() {
        flag = false;
    }

    public static void main(String[] args) {
        try {
            new ChatSocketChannel().startClient();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
